﻿using System;
using System.Collections.Generic;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Data.Entity;
using Domain;
using Domain.Specification;


namespace Data.Infrastructure
{
    public abstract class RepositoryBase<T,TPageData>: IRepository<T, PageData<T>> where T : class, new()
    {
        private DbEntityContext dataContext;
        private readonly IDbSet<T> dbset;
        protected RepositoryBase(IDatabaseFactory databaseFactory)
        {
            DatabaseFactory = databaseFactory;
            dbset = DataContext.Set<T>();
        }

        protected IDatabaseFactory DatabaseFactory
        {
            get;
            private set;
        }

        protected DbEntityContext DataContext
        {
            get { return dataContext ?? (dataContext = DatabaseFactory.Get()); }
        }

        //public virtual void Commit()
        //{
        //    dataContext.Commit();
        //}

        public virtual void Add(T entity)
        {
            dbset.Add(entity);
            //dataContext.Commit();
        }

        public virtual void Update(T entity)
        {
            dbset.Attach(entity);
            dataContext.Entry(entity).State = EntityState.Modified;
            //DbEntityEntry<T> entry = dataContext.Entry(entity);
            //entry.State = EntityState.Modified;
        }

        public virtual void Delete(T entity)
        {
            dbset.Remove(entity);
        }
        public void Delete(Func<T, Boolean> where)
        {
            IEnumerable<T> objects = dbset.Where<T>(where).AsEnumerable();
            foreach (T obj in objects)
                dbset.Remove(obj);
        }
        public virtual T GetById(int id)
        {
            return dbset.Find(id);
        }

        public virtual IQueryable<T> GetAll()
        {

            return dbset;
        }
        public virtual IEnumerable<T> GetMany(Func<T, bool> where)
        {
            return dbset.Where(where).ToList();
        }
        public T Get(Func<T, Boolean> where)
        {
            return dbset.Where(where).FirstOrDefault<T>();
        }

        public PageData<T> Get<S>(int pageIndex, int pageSize,
                       Expression<Func<T, S>> orderByExpression, bool isDesc)
        {
            var query = isDesc
               ?
               dbset.OrderByDescending(orderByExpression)
               :
               dbset.OrderBy(orderByExpression);

            PageData<T> pageData = new PageData<T>();
            pageData.TotalCount = query.Count();
            pageData.DataList = query.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();

            return pageData;
        }

        public PageData<T> Get<S>(int pageIndex, int pageSize, ISpecification<T> condition,
                               Expression<Func<T, S>> orderByExpression, bool isDesc)
        {
            var query = isDesc
               ?
               dbset.Where(condition.SatisfiedBy()).OrderByDescending(orderByExpression)
               :
               dbset.Where(condition.SatisfiedBy()).OrderBy(orderByExpression);

            PageData<T> pageData = new PageData<T>();
            pageData.TotalCount = query.Count();
            pageData.DataList = query.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();

            return pageData;
        }

        public List<T> GetListByTopN<S>(int topN, ISpecification<T> condition, Expression<Func<T, S>> orderByExpression, bool isDesc)
        {

            var query = isDesc
                ?
                dbset.Where(condition.SatisfiedBy()).OrderByDescending(orderByExpression).Take(topN)
                :
               dbset.Where(condition.SatisfiedBy()).OrderBy(orderByExpression).Take(topN);

            return query.ToList();

        }
    }
}
